home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / err87_13.zip / DECODE87.PAS next >
Pascal/Delphi Source File  |  1991-02-04  |  14KB  |  449 lines

  1. {$N+}
  2. unit decode87;
  3.  
  4.   { Unit to classify an 8087 instruction by its encoding }
  5. interface
  6. type
  7.   instruction =
  8.   (iF2XM1, iFABS, iFADD, iFADDP, iFBLD, iFBSTP, iFCHS, iFCLEX, iFCOM,
  9.    iFCOMP, iFCOMPP, iFCOS, iFDECSTP, iFDISI, iFDIV, iFDIVP, iFDIVR, iFDIVRP,
  10.    iFENI, iFFREE, iFIADD, iFICOM, iFICOMP, iFIDIV, iFIDIVR, iFILD, iFIMUL,
  11.    iFINCSTP, iFINIT, iFIST, iFISTP, iFISUB, iFISUBR, iFLD, iFLD1, iFLDCW,
  12.    iFLDENV, iFLDL2E, iFLDL2T, iFLDLG2, iFLDLN2, iFLDPI, iFLDZ, iFMUL, iFMULP,
  13.    iFNOP, iFPATAN, iFPREM, iFPREM1, iFPTAN, iFRNDINT, iFRSTOR, iFSAVE,
  14.    iFSCALE, iFSETPM, iFSIN, iFSINCOS, iFSQRT, iFST, iFSTCW, iFSTENV, iFSTP,
  15.    iFSTSW, iFSUB, iFSUBP, iFSUBR, iFSUBRP, iFTST, iFUCOM, iFUCOMP,
  16.    iFUCOMPP, iFXAM, iFXCH, iFXTRACT, iFYL2X, iFYL2XP1, iUnknown);
  17. const
  18.   inst_names : array[instruction] of String[7] =
  19.   ('F2XM1', 'FABS', 'FADD', 'FADDP', 'FBLD', 'FBSTP', 'FCHS', 'FCLEX', 'FCOM',
  20.    'FCOMP', 'FCOMPP', 'FCOS', 'FDECSTP', 'FDISI', 'FDIV', 'FDIVP', 'FDIVR', 'FDIVRP', 'FENI',
  21.    'FFREE', 'FIADD', 'FICOM', 'FICOMP', 'FIDIV', 'FIDIVR', 'FILD', 'FIMUL', 'FINCSTP',
  22.    'FINIT', 'FIST', 'FISTP', 'FISUB', 'FISUBR', 'FLD', 'FLD1', 'FLDCW', 'FLDENV', 'FLDL2E',
  23.    'FLDL2T', 'FLDLG2', 'FLDLN2', 'FLDPI', 'FLDZ', 'FMUL', 'FMULP', 'FNOP', 'FPATAN',
  24.    'FPREM', 'FPREM1', 'FPTAN', 'FRNDINT', 'FRSTOR', 'FSAVE', 'FSCALE', 'FSETPM', 'FSIN', 'FSINCOS', 'FSQRT', 'FST', 'FSTCW',
  25.    'FSTENV', 'FSTP', 'FSTSW', 'FSUB', 'FSUBP', 'FSUBR', 'FSUBRP', 'FTST', 'FUCOM',
  26.    'FUCOMP', 'FUCOMPP', 'FXAM', 'FXCH', 'FXTRACT', 'FYL2X', 'FYL2XP1', '');
  27. type
  28.   reg_count = 0..8;
  29.  
  30.   operand_type = (arReg0, arReg1, arReg2, arReg3, arReg4, arReg5, arReg6,
  31.                   arReg7, arWord, arLongint, arComp, arBCD,
  32.                   arSingle, arDouble, arExtended, arControl, arStatus,
  33.                   arEnviron, arState, arNone);
  34.   operand_set = set of operand_type;
  35. const
  36.   arg_names : array[operand_type] of String[8] =
  37.   ('Reg0', 'Reg1', 'Reg2', 'Reg3', 'Reg4', 'Reg5', 'Reg6',
  38.    'Reg7', 'Word', 'Longint', 'Comp', 'BCD',
  39.    'Single', 'Double', 'Extended', 'Control', 'Status',
  40.    'Environ', 'State', 'None');
  41.  
  42. type
  43.   opcode_info = record
  44.                   inst     : instruction;
  45.                   arg1, arg2 : operand_type;
  46.                 end;
  47.  
  48. procedure decode_opcode(opcode : Word; var result : opcode_info);
  49.  
  50. procedure operands_read(inst_info : opcode_info; var ops_read : operand_set);
  51.  
  52. function num_pops(inst_info : opcode_info) : reg_count;
  53.  
  54. function num_pushes(inst_info : opcode_info) : reg_count;
  55.  
  56. function limited(inst_info : opcode_info): boolean;
  57.  
  58. function lower_limit(inst_info : opcode_info) : extended;
  59.   { least legal operand }
  60.  
  61. function upper_limit(inst_info : opcode_info) : extended;
  62.   { greatest legal operand }
  63.  
  64.  
  65. implementation
  66. const
  67.   Plus_Infinity_Array : array[1..2] of word = (0, $7f80);
  68. var
  69.   Plus_Infinity : single absolute Plus_Infinity_Array;
  70. const
  71.   Minus_Infinity_Array : array[1..2] of word = (0, $ff80);
  72. var
  73.   Minus_Infinity : single absolute Minus_Infinity_Array;
  74.  
  75.   procedure operands_read(inst_info : opcode_info; var ops_read : operand_set);
  76.   const
  77.     reads_reg0 =
  78.     [iF2XM1, iFABS, iFADD, iFADDP, iFBSTP, iFCHS, iFCOM,
  79.     iFCOMP, iFCOMPP, iFCOS, iFDIV, iFDIVP, iFDIVR, iFDIVRP,
  80.     iFIADD, iFICOM, iFICOMP, iFIDIV, iFIDIVR, iFIMUL,
  81.     iFIST, iFISTP, iFISUB, iFISUBR, iFMUL, iFMULP,
  82.     iFPATAN, iFPREM, iFPREM1, iFPTAN, iFRNDINT,
  83.     iFSCALE, iFSIN, iFSINCOS, iFSQRT, iFST, iFSTP,
  84.     iFSUB, iFSUBP, iFSUBR, iFSUBRP, iFTST, iFUCOM, iFUCOMP,
  85.     iFUCOMPP, iFXAM, iFXCH, iFXTRACT, iFYL2X, iFYL2XP1];
  86.     reads_reg1 =
  87.     [iFPATAN, iFPREM, iFSCALE, iFYL2X, iFYL2XP1];
  88.     reads_arg1 =
  89.     [iFADD, iFADDP, iFBLD, iFCOM, iFCOMP, iFCOMPP, iFDIV, iFDIVP,
  90.     iFDIVR, iFDIVRP, iFIADD, iFICOM, iFICOMP, iFIDIV, iFIDIVR, iFILD, iFIMUL,
  91.     iFISUB, iFISUBR, iFLD, iFLDCW, iFLDENV, iFMUL, iFMULP,
  92.     iFRSTOR, iFSUB, iFSUBP, iFSUBR, iFSUBRP, iFTST, iFUCOM, iFUCOMP,
  93.     iFUCOMPP, iFXAM, iFXCH];
  94.  
  95.   begin
  96.     with inst_info do
  97.     begin
  98.       if inst in reads_reg0 then
  99.         ops_read := [arReg0]
  100.       else
  101.         ops_read := [];
  102.       if inst in reads_reg1 then
  103.         ops_read := ops_read+[arReg1];
  104.       if (arg1 <> arNone) and (inst in reads_arg1) then
  105.         ops_read := ops_read+[arg1];
  106.       if arg2 <> arNone then
  107.         ops_read := ops_read+[arg2];
  108.     end;
  109.   end;
  110.  
  111.   function num_pops(inst_info : opcode_info) : reg_count;
  112.   const
  113.     two_pop  = [iFCOMPP, iFUCOMPP];
  114.     pops =
  115.     [iFADDP, iFBSTP, iFCOMP, iFDIVP, iFDIVRP, iFICOMP, iFISTP, iFMULP,
  116.     iFPATAN, iFSTP, iFSUBP, iFSUBRP, iFUCOMP, iFYL2X, iFYL2XP1]+two_pop;
  117.   begin
  118.     if inst_info.inst in pops then
  119.       if inst_info.inst in two_pop then
  120.         num_pops := 2
  121.       else
  122.         num_pops := 1
  123.     else
  124.       num_pops := 0;
  125.   end;
  126.  
  127.   function num_pushes(inst_info : opcode_info) : reg_count;
  128.   const
  129.     does_push =
  130.     [iFBLD, iFILD, iFLD, iFLD1, iFLDL2E, iFLDL2T, iFLDLG2, iFLDLN2,
  131.     iFLDPI, iFLDZ, iFPTAN, iFSINCOS, iFXTRACT];
  132.   begin
  133.     if inst_info.inst in does_push then
  134.       num_pushes := 1
  135.     else
  136.       num_pushes := 0;
  137.   end;
  138.  
  139. function limited(inst_info:opcode_info):boolean;
  140. const
  141.   limited_instructions =
  142.   [iF2XM1 {0 to 0.5} , iFPATAN {0 < Y < X < pinf} ,
  143.   iFPTAN {0 to pi/4} , iFSCALE {won't cause exception, but -2^15<Y<2^15} ,
  144.   iFSQRT {0 to pinf} , iFYL2X {0 < X < pinf} ,
  145.   iFYL2XP1 {|X| < (1-1/sqrt(2))} ];
  146. begin
  147.   limited := inst_info.inst in limited_instructions;
  148. end;
  149.  
  150.  
  151.   function lower_limit(inst_info : opcode_info) : extended;
  152.   begin
  153.     if limited(inst_info) then
  154.       case inst_info.inst of
  155.         iF2XM1,
  156.         iFPATAN,
  157.         iFPTAN,
  158.         iFSQRT,
  159.         iFYL2X : lower_limit := 0.0;
  160.         iFSCALE : lower_limit := -32768;
  161.         iFYL2XP1 : lower_limit := -(1-1/Sqrt(2));
  162.       end
  163.     else
  164.       lower_limit := minus_infinity;
  165.   end;
  166.  
  167.   function upper_limit(inst_info : opcode_info) : extended;
  168.   begin
  169.     if limited(inst_info)  then
  170.       case inst_info.inst of
  171.         iF2XM1 : upper_limit := 0.5;
  172.         iFSQRT,
  173.         iFYL2X,
  174.         iFPATAN : upper_limit := plus_infinity;
  175.         iFPTAN : upper_limit := pi/4;
  176.         iFSCALE : upper_limit := 32768;
  177.         iFYL2XP1 : upper_limit := (1-1/Sqrt(2));
  178.       end
  179.     else
  180.       upper_limit := plus_infinity;
  181.   end;
  182.   procedure decode_opcode(opcode : Word; var result : opcode_info);
  183.  
  184.   { This routine and those within it are closely based on UNINLINE,
  185.     by L. David Baldwin. }
  186.  
  187.   var
  188.     opbyte1,
  189.     opbyte2,
  190.     rm,
  191.     mode,
  192.     middle   : Byte;
  193.     memory_reference : Boolean;
  194.  
  195.     procedure ReadModeByte;
  196.     {read the mode byte and sort out the various parts.  read the
  197.      displacement byte or word if req'D}
  198.     var Modebyte : Byte;
  199.     begin
  200.       Modebyte := opbyte2;
  201.       rm := Modebyte and 7;
  202.       mode := (Modebyte and $C0) div 64;
  203.       middle := (Modebyte and $38) div 8;
  204.       if (mode = 0) and (rm = 6) or (mode = 2) or (mode = 1) then
  205.         memory_reference := True;
  206.     end;
  207.  
  208.     procedure ST_i;               {do st(i) }
  209.     begin
  210.       result.arg1 := operand_type(Word(rm));
  211.     end;
  212.  
  213.     procedure STi_ST;             {do st(i),st }
  214.     begin
  215.       ST_i;
  216.       result.arg2 := arReg0;
  217.     end;
  218.  
  219.     procedure ST_STi;             { do st,st(i) }
  220.     begin
  221.       ST_i;
  222.       with result do
  223.       begin
  224.         arg2 := arg1;
  225.         arg1 := arReg0;
  226.       end;
  227.     end;
  228.  
  229.     procedure DB;
  230.     const inst_list : array[0..12] of instruction =
  231.       (iFILD, iUnknown, iFIST, iFISTP, iUnknown, iFLD, iUnknown,
  232.        iFSTP, iFENI, iFDISI, iFCLEX, iFINIT, iFSETPM);
  233.     var I    : Word;
  234.       Tmp      : instruction;
  235.     begin
  236.       ReadModeByte;
  237.       if (mode = 3) then
  238.         I := rm+8
  239.       else
  240.         I := middle;              {form an index}
  241.       Tmp := inst_list[I];
  242.       if (Tmp <> iUnknown) and (I <= 12) then
  243.       begin
  244.         result.inst := Tmp;
  245.         if I <= 3 then
  246.           result.arg1 := arLongint
  247.         else
  248.           if I <= 7 then
  249.             result.arg1 := arExtended
  250.       end
  251.       else
  252.         { Unknown! };
  253.     end;
  254.  
  255.     procedure DD;
  256.     const inst_list : array[0..13] of instruction =
  257.       (iFLD, iUnknown, iFST, iFSTP, iFRSTOR,
  258.        iUnknown, iFSAVE, iFSTSW, iFFREE, iFXCH,
  259.        iFST, iFSTP, iFUCOM, iFUCOMP);
  260.     var I    : Word;
  261.       Tmp      : instruction;
  262.     begin
  263.       ReadModeByte;
  264.       if mode = 3 then
  265.         I := middle+8
  266.       else
  267.         I := middle;
  268.       Tmp := inst_list[I];
  269.       if (Tmp <> iUnknown) and (I <= 13) then
  270.       begin
  271.         result.inst := Tmp;
  272.         if I <= 3 then
  273.           result.arg1 := arDouble
  274.         else if I <= 7 then
  275.           if I in [4, 6] then
  276.             result.arg1 := arState
  277.           else
  278.             result.arg1 := arStatus
  279.         else
  280.           ST_i;
  281.       end
  282.       else
  283.         { Unknown !};
  284.     end;
  285.  
  286.     procedure DF;
  287.     const inst_list : array[0..11] of instruction =
  288.       (iFILD, iUnknown, iFIST, iFISTP, iFBLD,
  289.        iFILD, iFBSTP, iFISTP, iFFREE, iFXCH,
  290.        iFST, iFSTP);
  291.     var I    : Word;
  292.     begin
  293.       ReadModeByte;
  294.       if mode = 3 then
  295.         I := middle+8
  296.       else
  297.         I := middle;              {form index}
  298.       if (I <> 1) and (I <= 11) then
  299.       begin
  300.         result.inst := inst_list[I];
  301.         if I <= 3 then
  302.           result.arg1 := arWord
  303.         else
  304.           if I <= 7 then
  305.           begin
  306.             if (I and 5) = 4 then
  307.               result.arg1 := arBCD
  308.             else
  309.               result.arg1 := arComp;
  310.           end
  311.         else
  312.           ST_i;
  313.       end
  314.       else
  315.         { Unknown !};
  316.     end;
  317.  
  318.     procedure D9;
  319.     const inst_list1 : array[0..11] of instruction =
  320.       (iFLD, iUnknown, iFST, iFSTP,
  321.        iFLDENV, iFLDCW, iFSTENV, iFSTCW,
  322.        iFLD, iFXCH, iFNOP, iFSTP);
  323.  
  324.     const inst_list2 : array[0..31] of instruction =
  325.       (iFCHS, iFABS, iUnknown, iUnknown, iFTST,
  326.        iFXAM, iUnknown, iUnknown, iFLD1, iFLDL2T,
  327.        iFLDL2E, iFLDPI, iFLDLG2, iFLDLN2, iFLDZ,
  328.        iUnknown, iF2XM1, iFYL2X, iFPTAN, iFPATAN,
  329.        iFXTRACT, iFPREM1, iFDECSTP, iFINCSTP, iFPREM,
  330.        iFYL2XP1, iFSQRT, iFSINCOS, iFRNDINT, iFSCALE,
  331.        iFSIN, iFCOS);
  332.     var I    : Word;
  333.       Tmp      : instruction;
  334.     begin
  335.       ReadModeByte;
  336.       if (mode <> 3) or (middle <= 3) then
  337.       begin
  338.         if mode = 3 then
  339.           I := middle+8
  340.         else
  341.           I := middle;
  342.         if (I = 1) or ((I = 10) and (rm <> 0)) then
  343.           { Unknown !}
  344.         else
  345.         begin
  346.           Tmp := inst_list1[I];
  347.           result.inst := Tmp;
  348.           if I <= 3 then
  349.             result.arg1 := arSingle
  350.           else if I <= 7 then
  351.             if I in [4, 6] then
  352.               result.arg1 := arEnviron
  353.             else
  354.               result.arg1 := arControl
  355.           else
  356.             if I <> 10 then       {fnop is 10}
  357.               ST_i;               {st(i)}
  358.         end;
  359.       end
  360.       else
  361.       begin                       {mode=3 and middle>=4}
  362.         I := rm+(middle and 3)*8; {include lower 2 bits of middle in index}
  363.         if (inst_list2[I] <> iUnknown) and (I <= 31) then
  364.           result.inst := inst_list2[I]
  365.         else
  366.           { unknown! };
  367.       end;
  368.     end;
  369.  
  370.     procedure D8_DC;
  371.     type Nametype = array[0..7] of instruction;
  372.     var Shortreal : Boolean;
  373.     const inst_list : Nametype = (
  374.       iFADD, iFMUL, iFCOM, iFCOMP, iFSUB, iFSUBR, iFDIV, iFDIVR);
  375.     begin
  376.       Shortreal := opbyte1 = $D8;
  377.       ReadModeByte;
  378.       if not Shortreal then
  379.         if (middle >= 6) then     {fdiv, fdivr are reversed here}
  380.           middle := middle xor 1;
  381.       result.inst := inst_list[middle];
  382.       if mode <> 3 then
  383.       begin
  384.         if Shortreal then
  385.           result.arg1 := arSingle
  386.         else
  387.           result.arg1 := arDouble
  388.       end
  389.       else                        {mode=3}
  390.         if Shortreal then
  391.           ST_STi
  392.       else
  393.         STi_ST;                   {add the stack info}
  394.     end;
  395.  
  396.     procedure DA_DE;
  397.     type Nametype = array[0..15] of instruction;
  398.     var ShortInt : Boolean;
  399.     const inst_list : Nametype = (
  400.       iFIADD, iFIMUL, iFICOM, iFICOMP, iFISUB, iFISUBR, iFIDIV,
  401.       iFIDIVR, iFADDP, iFMULP, iFCOMP, iFCOMPP, iFSUBRP, iFSUBP,
  402.       iFDIVRP, iFDIVP);
  403.     begin
  404.       ShortInt := opbyte1 = $DA;
  405.       ReadModeByte;
  406.       if mode <> 3 then
  407.       begin
  408.         result.inst := inst_list[middle];
  409.         if ShortInt then
  410.           result.arg1 := arLongint
  411.         else
  412.           result.arg1 := arWord;
  413.       end
  414.       else
  415.       begin                       {mode=3}
  416.         if ((middle = 3) and (rm <> 1)) then
  417.           { Unknown! }                  {not fl pt}
  418.         else
  419.           if ShortInt and (rm = 1) and (middle = 5) then
  420.             result.inst := iFUCOMPP
  421.         else
  422.         begin
  423.           result.inst := inst_list[middle+8];
  424.           if (middle <> 3) then
  425.             STi_ST;
  426.         end;
  427.       end;
  428.     end;
  429.  
  430.   begin                           { decode_opcode}
  431.     opbyte1 := Hi(opcode);
  432.     opbyte2 := Lo(opcode);
  433.     with result do
  434.     begin
  435.       inst := iUnknown;
  436.       arg1 := arNone;
  437.       arg2 := arNone;
  438.       case opbyte1 of
  439.         $DA, $DE : DA_DE;
  440.         $D8, $DC : D8_DC;
  441.         $D9 : D9;
  442.         $DB : DB;
  443.         $DD : DD;
  444.         $DF : DF;
  445.       end;
  446.     end;
  447.   end;
  448. end.
  449.